package com.ymttest.business.service.shenqi;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.ymttest.database.sharding.db.sharding.model.*;
import org.apache.http.client.ClientProtocolException;
import org.json.JSONObject;

import com.shop2cn.iapi.sqoptrade.parameter.enums.SqSellerRoleEnum;
import com.shop2cn.iapi.sqoptrade.parameter.req.ConfirmApplyRefundReq;
import com.shop2cn.iapi.sqoptrade.parameter.req.GetRefundMaxAmountsReq;
import com.shop2cn.iapi.sqoptrade.parameter.utill.Utils;
import com.shop2cn.iapi.sqoptrade.resp.Order;
import com.shop2cn.iapi.sqoptrade.service.ConfirmApplyRefundCall;
import com.shop2cn.iapi.sqoptrade.service.GetRefundMaxAmountsCall;
import com.shop2cn.iapi.sqrefund.parameter.AuditRefundReq;
import com.shop2cn.iapi.sqrefund.parameter.FullRefundGoodsReq;
import com.shop2cn.iapi.sqrefund.parameter.FullRefundReq;
import com.shop2cn.iapi.sqrefund.parameter.PartAmountRefundReq;
import com.shop2cn.iapi.sqrefund.parameter.PartProductRefundReq;
import com.shop2cn.iapi.sqrefund.parameter.SaveOrUpdateRefundGoodsExpressInfoListReq;
import com.shop2cn.iapi.sqrefund.parameter.bean.PartProductRefundVo;
import com.shop2cn.iapi.sqrefund.parameter.bean.RefundAddressVo;
import com.shop2cn.iapi.sqrefund.parameter.bean.RefundGoodsExpressInfoVo;
import com.shop2cn.iapi.sqrefund.service.AuditRefundCall;
import com.shop2cn.iapi.sqrefund.service.FullRefundCall;
import com.shop2cn.iapi.sqrefund.service.FullRefundGoodsCall;
import com.shop2cn.iapi.sqrefund.service.PartAmountRefundCall;
import com.shop2cn.iapi.sqrefund.service.PartProductRefundCall;
import com.shop2cn.iapi.sqrefund.service.SaveOrUpdateRefundGoodsExpressInfoListCall;
import com.ymt.base.YmatouEasyCall;
import com.ymt.core.tool.Logger;
import com.ymttest.business.service.SQPayGateWayCallService;
import com.ymttest.business.service.shenqi.bean.ShenqiUserSet;
import com.ymttest.database.model.AccountEntry;
import com.ymttest.database.model.sqrefund.RefundBill;
import com.ymttest.database.model.sqrefund.RefundProductDetail;
import com.ymttest.database.sharding.db.sqlwapper.OrderShardingWapper;
import com.ymttest.database.sqlwapper.AccountWapper;
import com.ymttest.database.sqlwapper.sqrefund.RefundBillWrapper;
import com.ymttest.database.sqlwapper.sqrefund.RefundProductDetailWrapper;
import com.ymttest.utils.DataUtil;
import com.ymttest.utils.TestDataManager;

public class RefundService {

	private static OrderShardingWapper orderShardingWapper = new OrderShardingWapper();

	private static RefundBillWrapper refundBillWrapper = new RefundBillWrapper();
	private static RefundProductDetailWrapper refundProductDetailWrapper = new RefundProductDetailWrapper();
	
	private static long macaoCDFGoodsOwnerId = ShenqiUserSet.macaoCDFGoodsOwnerId;

	public static HashMap<String, BigDecimal> getShenqiRefundAmount(
			Long orderId, Long sellerId, String catalogId, Integer productNum)
			throws Exception {

		GetRefundMaxAmountsReq req = new GetRefundMaxAmountsReq();

		req.setCatalogId(catalogId);
		req.setOrderId(orderId);
		req.setSellerId(sellerId);
		req.setProductCount(productNum);

		GetRefundMaxAmountsCall call = new GetRefundMaxAmountsCall();

		call.setData(req);
		call.callService();

		JSONObject object = new JSONObject(call.getReturnData());

		HashMap<String, BigDecimal> map = new HashMap<>();

		map.put("maxProductRefundAmount",
				new BigDecimal(object.optString("productMaxRefundAmount")));
		map.put("maxRefundFreight",
				new BigDecimal(object.optString("freightMaxRefundAmount")));
		map.put("maxRefundTax",
				new BigDecimal(object.optString("taxMaxRefundAmount")));

		return map;
	}

	public static ConfirmApplyRefundReq buildStandApplyRefundReq(Long orderId,
			Long sellerId, String catalogId, BigDecimal freightRefundAmount,
			BigDecimal taxRefundAmount, BigDecimal productRefundAmount,
			Integer productNum) {

		ConfirmApplyRefundReq req = new ConfirmApplyRefundReq();

		req.setOrderId(orderId);
		req.setCatalogId(catalogId);
		req.setFreightRefundAmount(freightRefundAmount);
		req.setProductCount(productNum);
		req.setProductRefundAmount(productRefundAmount);
		req.setSellerId(sellerId);
		req.setTaxRefundAmount(taxRefundAmount);

		return req;
	}

	public static void applyRefundCall(ConfirmApplyRefundReq applyRefundReq) {

		ConfirmApplyRefundCall applySalesRefundCall = new ConfirmApplyRefundCall();
		applySalesRefundCall.setData(false, applyRefundReq);

		try {

			applySalesRefundCall.callService();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 退款业务表（refund_bill）
	 * 
	 * @param expected
	 * @param actual
	 */
	public static void verifyRefundBillDb(RefundBillPo expected,
			RefundBillPo actual) {

		Logger.comment(String.format("校验订单库退款业务表（refund_bill） refundBillNo : %s",
				actual.getRefundBillNo()));

		verify(expected.getFreight(), actual.getFreight(), "验证数据库Freight");

		verify(true, Utils.calcTimeSpanMin(actual.getAddTime()) < 3,
				"验证数据库AddTime跟系统当前时间差为3分钟内");

		verify(true, Utils.calcTimeSpanMin(actual.getAddTime()) < 3,
				"验证数据库UpdateTime跟系统当前时间差为3分钟内");

		verify(expected.getOrderId(), actual.getOrderId(), "验证数据库OrderId");
		verify(expected.getSellerId(), actual.getSellerId(), "验证数据库SellerId");
		verify(expected.getUserId(), actual.getUserId(), "验证数据库UserId");
		verify(expected.getThirdpartyDiscount() == null ? BigDecimal.ZERO
				: expected.getThirdpartyDiscount(),
				actual.getThirdpartyDiscount(), "验证数据库ThirdpartyDiscount");
		verify(expected.getCatalogId(), actual.getCatalogId(), "验证数据库CatalogId");
		verify(expected.getProductCount(), actual.getProductCount(),
				"验证数据库ProductCount");
		verify(expected.getRefundBillStatus(), actual.getRefundBillStatus(),
				"验证数据库RefundBillStatus");
		verify(expected.getTopspeedRefund(), actual.getTopspeedRefund(),
				"验证数据库TopspeedRefund");
		verify(expected.getDeductedCouponAmount() == null ? BigDecimal.ZERO
				: expected.getDeductedCouponAmount(),
				actual.getDeductedCouponAmount(), "验证数据库DeductedCouponAmount");
		verify(expected.getNoSettlementCouponAmount() == null ? BigDecimal.ZERO
				: expected.getNoSettlementCouponAmount(),
				actual.getNoSettlementCouponAmount(),
				"验证数据库NoSettlementCouponAmount");

		verify(expected.getAfterReceiving(), actual.getAfterReceiving(),
				"验证数据库AfterReceiving");
		verify(expected.getRefundBillNo(), actual.getRefundBillNo(),
				"验证数据库RefundBillNo");

		verify(expected.getTotalAmount(), actual.getTotalAmount(),
				"验证数据库TotalAmount");

		verify(expected.getAccountAmount() == null ? BigDecimal.ZERO
				: expected.getAccountAmount(), actual.getAccountAmount(),
				"验证数据库accountAmount");

		verify(expected.getCardAmount() == null ? BigDecimal.ZERO
				: expected.getCardAmount(), actual.getCardAmount(),
				"验证数据库cardAmount");

		verify(expected.getThirdpartyAmount() == null ? BigDecimal.ZERO
				: expected.getThirdpartyAmount(), actual.getThirdpartyAmount(),
				"验证数据库thirdpartyAmount");

		verify(expected.getRefundStatus(), actual.getRefundStatus(),
				"验证数据库RefundStatus");

		verify(expected.getRebateAmount() == null ? BigDecimal.ZERO
				: expected.getRebateAmount(), actual.getRebateAmount(),
				"验证数据库rebateAmount");

		verify(expected.getFailCode(), actual.getFailCode(), "验证数据库FailCode");
		verify(expected.getFailReason(), actual.getFailReason(),
				"验证数据库FailReason");
		verify(expected.getTax() == null ? BigDecimal.ZERO : expected.getTax(),
				actual.getTax(), "验证数据库tax");
		verify(expected.getProductAmount() == null ? BigDecimal.ZERO
				: expected.getProductAmount(), actual.getProductAmount(),
				"验证数据库ProductAmount");
		
		verify(expected.getRefundIntegral(), actual.getRefundIntegral(),
				"验证数据库RefundIntegral");
		
		verify(expected.getReturnStockStatus(), actual.getReturnStockStatus(),
				"验证数据库ReturnStockStatus");
		
		verify(expected.getApplierId(), actual.getApplierId(),
				"验证数据库ApplierId");
		verify(expected.getOverSell(), actual.getOverSell(),
				"验证数据库OverSell");
	}
	
	public static void buildUserRefundFundDetail(RefundBill refundBill,
			Long paymentId, boolean isAccountPaid,
			BigDecimal refundServiceAmount) {
		
		UserRefundFundDetailPo expected = new UserRefundFundDetailPo();
		
		Long integral = refundBill.getTotal_refund_integral();
		
		BigDecimal amount = refundBill.getTotal_refund_freight_amount()
				.add(refundBill.getTotal_refund_product_amount())
				.add(refundBill.getTotal_refund_tax_amount())
				.add(refundServiceAmount);
		
		expected.setOrderId(refundBill.getOrder_id());
		expected.setPaymentId(paymentId);
		expected.setBizType(1);
		expected.setMemo(null);

		PaymentPo paymentPo = orderShardingWapper.selectPaymentById(paymentId);

		if (Utils.zeroIfNull(paymentPo.getRealSubmitForeignAmount()).compareTo(BigDecimal.ZERO) == 1)
			if (Utils.zeroIfNull(paymentPo.getPayableAmount()).compareTo(amount) == 0)
				amount = paymentPo.getRealSubmitForeignAmount();
			else
				amount = amount.multiply(new BigDecimal(paymentPo.getExchangeRate()))
						.setScale(2, BigDecimal.ROUND_HALF_UP);
		
		// 中免澳门支付时，无法mock，无法退金额
		if (refundBill.getSeller_id() == macaoCDFGoodsOwnerId)
			expected.setThirdpartyRefundStatus(2);
		
		if (isAccountPaid) {
			
			expected.setAccountAmount(amount);
			expected.setAccountRefundStatus(4);
			expected.setThirdpartyAmount(BigDecimal.ZERO);
			expected.setThirdpartyRefundStatus(-1);
		} else {
			
			expected.setAccountAmount(BigDecimal.ZERO);
			expected.setAccountRefundStatus(-1);
			expected.setThirdpartyAmount(amount);
			expected.setThirdpartyRefundStatus(4);
		}
		
		if (integral.longValue() != 0) {
			
			expected.setThirdpartyRefundStatus(4);
			expected.setIntegralRefundStatus(4);
		}
		
		expected.setIsShenqi(true);
		expected.setRefundIntegral(integral);
		
		UserRefundFundDetailPo actual = orderShardingWapper
				.selectShenqiUserRefundFundDetailByBizno(refundBill
						.getRefund_no());
		
		RefundService.verifyUserRefundFundDetailDb(expected, actual);
		
		if (isAccountPaid) {
			
			AccountWapper accountWapper = new AccountWapper();
			
			HashMap<String, Object> accountEntryMap = new HashMap<>();

			accountEntryMap.put("userId", refundBill.getUser_id());
			accountEntryMap.put("bizcode", "300055");
			accountEntryMap.put("originalNo", refundBill.getUser_id());
			accountEntryMap.put("accountType", "93");
			accountEntryMap.put("bizno", refundBill.getRefund_no());

			AccountEntry accountEntry = accountWapper.selectAccountEntryByMap(
					accountEntryMap).get(0);
			
			DataUtil.verifyDecimalEquals(amount,
					accountEntry.getAmount(), "验证Amount");
		}
	}

	/**
	 * 用户退款资金详情表（user_refund_fund_detail）
	 * 
	 * @param expected
	 * @param actual
	 */
	public static void verifyUserRefundFundDetailDb(
			UserRefundFundDetailPo expected, UserRefundFundDetailPo actual) {
		
		// 如果买家没有支付任何金额，则不校验user_refund_fund_detail
		if (expected.getThirdpartyAmount().compareTo(BigDecimal.ZERO) == 0
				&& expected.getAccountAmount().compareTo(BigDecimal.ZERO) == 0)
			return;
		
		Logger.comment(String
				.format("验证退用户退款资金详情表（user_refund_fund_detail） OrderId :%s payment_id :%s",
						expected.getOrderId(), expected.getPaymentId()));

//		verify(true, Utils.calcTimeSpanMin(actual.getUpdateTime()) < 3,
//				"验证数据库UpdateTime跟系统当前时间差为3分钟内");
		verify(true, Utils.calcTimeSpanMin(actual.getAddTime()) < 3,
				"验证数据库AddTime跟系统当前时间差为3分钟内");

		verify(expected.getBizType(), actual.getBizType(), "验证数据库BizType");
		verify(expected.getPaymentId(), actual.getPaymentId(), "验证数据库PaymentId");

		verify(expected.getMemo(),
				actual.getMemo() == null ? "0" : actual.getMemo(), "验证数据库Memo");

		verify(expected.getAccountAmount(), actual.getAccountAmount(),
				"验证数据库AccountAmount");

		verify(expected.getAccountRefundStatus(),
				actual.getAccountRefundStatus(), "验证数据库AccountRefundStatus");

		verify(expected.getThirdpartyAmount(), actual.getThirdpartyAmount(),
				"验证数据库ThirdpartyAmount");
		verify(expected.getThirdpartyRefundStatus(),
				actual.getThirdpartyRefundStatus(),
				"验证数据库ThirdpartyRefundStatus");

		verify(expected.getThirdpartyDiscount() == null ? BigDecimal.ZERO
				: expected.getThirdpartyDiscount(),
				actual.getThirdpartyDiscount(), "验证数据库ThirdpartyDiscount");

		verify(expected.getRebateAmount() == null ? BigDecimal.ZERO
				: expected.getRebateAmount(), actual.getRebateAmount(),
				"验证数据库RebateAmount");

		verify(true,
				Utils.calcTimeSpanMin(actual.getThirdpartyRefundTime()) < 2,
				"验证数据库ThirdpartyRefundTime跟系统当前时间差为2分钟内");

		verify(expected.getIsShenqi(), actual.getIsShenqi(), "验证数据库IsShenqi");
		
		verify(expected.getIntegralRefundStatus(), actual.getIntegralRefundStatus(), "验证数据库IntegralRefundStatus");
		verify(expected.getRefundIntegral(), actual.getRefundIntegral(), "验证数据库RefundIntegral");
	}

	/**
	 * 退款业务表（refund_fund）
	 * 
	 * @param expected
	 * @param actual
	 */
	public static void verifyRefundFundDb(RefundFundPo expected,
			RefundFundPo actual) {

		Logger.comment(String.format("验证退款业务表（refund_fund） OrderId :%s",
				expected.getOrderId()));

		verify(expected.getFreight(), actual.getFreight(), "验证数据库Freight");

		verify(true, Utils.calcTimeSpanMin(actual.getAddTime()) < 2,
				"验证数据库AddTime跟系统当前时间差为2分钟内");

		verify(true, Utils.calcTimeSpanMin(actual.getAddTime()) < 2,
				"验证数据库UpdateTime跟系统当前时间差为2分钟内");

		verify(expected.getOrderId(), actual.getOrderId(), "验证数据库OrderId");

		verify(expected.getDeductedCouponAmount() == null ? BigDecimal.ZERO
				: expected.getDeductedCouponAmount(),
				actual.getDeductedCouponAmount(), "验证数据库DeductedCouponAmount");

		verify(expected.getUserThirdpartyAmount(),
				actual.getUserThirdpartyAmount(), "验证数据库thirdpartyAmount");
		verify(expected.getUserAccountAmount(), actual.getUserAccountAmount(),
				"验证数据库userAccountAmount");

		verify(expected.getThirdpartyDiscount() == null ? BigDecimal.ZERO
				: expected.getThirdpartyDiscount(),
				actual.getThirdpartyDiscount(), "验证数据库thirdpartyDiscount");

		verify(expected.getUserRebateAmount() == null ? BigDecimal.ZERO
				: expected.getUserRebateAmount(), actual.getUserRebateAmount(),
				"验证数据库UserRebateAmount");
	}

	private static void verify(Object expected, Object actuaL, String desc) {

		if (expected instanceof java.math.BigDecimal) {
			DataUtil.verifyDecimalEquals(expected, actuaL, desc);
		} else {
			if (expected != null) {
				Logger.verifyEquals(expected, actuaL, desc);
			}
		}
	}

	/**
	 * 查询用户流水
	 * 
	 * @param userId
	 * @param bizno
	 * @param originalNo
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static AccountEntry getAccountEntry(long userId, String bizno,
			String originalNo) {

		Map m = new HashMap();

		m.put("userId", userId);
		m.put("bizno", bizno);
		m.put("originalNo", originalNo);
		m.put("bizcode", "300006");

		AccountEntry res = null;
		try {

			res = new AccountWapper().selectAccountEntryByBizNo(m).get(0);

		} catch (Exception e) {

			e.printStackTrace();
		}

		return res;
	}

	/**
	 * 查询用户流水
	 * 
	 * @param userId
	 * @param bizno
	 * @param originalNo
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static AccountEntry getRefundRebateAmountAccountEntry(long userId,
			String bizno, String originalNo) {

		Map m = new HashMap();

		m.put("userId", userId);
		m.put("bizno", bizno);
		m.put("originalNo", originalNo);
		m.put("bizcode", "300044");

		AccountEntry res = null;
		try {

			res = new AccountWapper().selectAccountEntryByBizNo(m).get(0);

		} catch (Exception e) {

			e.printStackTrace();
		}

		return res;
	}

	/**
	 * 运费退款 如果申请的退款金额小于商品的实际支付金额（不包括运费），则不退回运费
	 * 
	 * @param orderDetailPo
	 * @param applyRefundAmount
	 * @return
	 */
	public static BigDecimal apportionFreight(OrderDetailPo orderDetailPo,
			BigDecimal applyRefundAmount, int applyRefundCount) {

		BigDecimal singleProductRealPayAmount = Utils
				.zeroIfNull(orderDetailPo.getProductPrice())
				.multiply(new BigDecimal(orderDetailPo.getProductCount()))
				.subtract(Utils.zeroIfNull(orderDetailPo.getRebatePaidAmount()));

		BigDecimal refundFreight = applyRefundAmount.subtract(
				singleProductRealPayAmount.divide(
						new BigDecimal(orderDetailPo.getProductCount()), 20,
						RoundingMode.HALF_UP).multiply(
						new BigDecimal(applyRefundCount))).setScale(2,
				RoundingMode.HALF_UP);

		return refundFreight.compareTo(BigDecimal.ZERO) == -1 ? BigDecimal.ZERO
				: refundFreight;
	}

	/**
	 * 返点金额的退款
	 * 
	 * @param orderDetailPo
	 * @param applyRefundAmount
	 * @return
	 */
	public static BigDecimal apportionRefundRebate(OrderDetailPo orderDetailPo,
			BigDecimal applyRefundAmount) {

		BigDecimal productRealPayAmount = SqTradingCallService
				.getOrderDetailPaidAmountExcludeFreight(orderDetailPo);

		if (applyRefundAmount.compareTo(productRealPayAmount) >= 0)
			return orderDetailPo.getRebatePaidAmount();
		else
			return devideThenMultiply(applyRefundAmount, productRealPayAmount,
					Utils.zeroIfNull(orderDetailPo.getRebatePaidAmount()));
	}

	public static BigDecimal devideThenMultiply(BigDecimal dividend,
			BigDecimal divisor, BigDecimal multiplier) {
		return dividend.divide(divisor, MathContext.DECIMAL32)
				.multiply(multiplier).setScale(2, RoundingMode.HALF_UP);
	}

	/**
	 * 退款失败补偿
	 */
	public static void retryRefund() {

		YmatouEasyCall retryRefundCall = new YmatouEasyCall("", "POST", "JSON");

		String json = "{\"minuteBefore\":" + 0 + "}";

		retryRefundCall
				.setUrl("http://operate.trading.iapi.ymatou.com/api/SalesRefund/retryRefundInstruction");

		retryRefundCall.setData(json);

		Logger.comment("退款补偿");
		try {
			retryRefundCall.callService();

		} catch (Exception e) {

			e.printStackTrace();

		}
	}

	public static HashMap<Long, BigDecimal> getRefundedProfit(
			RefundBillPo refundBillPo, OrderPo orderPo) {

		Logger.comment("获取" + refundBillPo.getRefundBillNo() + "退款单利润");

		BigDecimal refundTotalAmount = refundBillPo.getTotalAmount();
		BigDecimal taxRefundAmount = refundBillPo.getTax();
		BigDecimal freightRefundAmount = refundBillPo.getFreight();

		Long orderId = orderPo.getOrderId();

		HashMap<Long, BigDecimal> refundedProfitHashMap = new HashMap<>();

		if (orderPo.getSellerId() == orderPo.getGoodsOwnerId()) {

			refundedProfitHashMap.put(orderPo.getGoodsOwnerId(),
					refundTotalAmount);

			if (orderPo.getSalesman() != 0) {

				refundedProfitHashMap.put(orderPo.getSalesman(),
						refundTotalAmount);
			}
		} else {

			String catalogId = refundBillPo.getCatalogId();
			Integer refundCount = refundBillPo.getProductCount();

			OrderDetailPo orderDetailPo = orderShardingWapper
					.selectOrderDetailbyOrderIdAndCatalogId(orderId, catalogId);
			Integer productCount = orderDetailPo.getProductCount();

			boolean isInherited = GodmchManageCallService
					.isInheritedAgent(orderPo.getSellerId());

			List<ShenqiProxyChainPo> shenqiProxyChain = isInherited ? SqTradingProductService
					.getInheritedProxyChainInfo(catalogId, orderPo.getSellerId()) : SqTradingProductService
					.getProxyChainInfoList(catalogId, orderPo.getSellerId());

			// 客服的收入
			BigDecimal serviceIncome = BigDecimal.ZERO;

			// 代理订单的运费不从订单上取，订单上的运费会被fullReductionFreeFreight影响
			BigDecimal productFreight = orderDetailPo.getFreight();

			int i = 1;

			for (ShenqiProxyChainPo chainPo : shenqiProxyChain) {

				// 店主的总收入
				BigDecimal shopOwnerProfit = CalculateShenqiSellerProfit
						.calProductProfit(orderDetailPo, isInherited, chainPo,
								shenqiProxyChain, orderPo, i,
								SqSellerRoleEnum.ShopOwner.getCode());
				// 货头的总收入
				BigDecimal goodsOwnerProfit = CalculateShenqiSellerProfit
						.calProductProfit(orderDetailPo, isInherited, chainPo,
								shenqiProxyChain, orderPo, i,
								SqSellerRoleEnum.GoodOwner.getCode());
				// 中间商的总收入
				BigDecimal middlerManProfit = CalculateShenqiSellerProfit
						.calProductProfit(orderDetailPo, isInherited, chainPo,
								shenqiProxyChain, orderPo, i,
								SqSellerRoleEnum.MiddlerMan.getCode());

				if (isInherited) {

					if (shenqiProxyChain.size() >= 3) {

						if (shenqiProxyChain.size() - 1 == i) {

							// 优惠总额：买手优惠券 + 买手满减优惠
							BigDecimal totalPromotion = orderDetailPo
									.getPromotionAmount().add(
											orderDetailPo
													.getSellerCouponAmount());

							middlerManProfit = middlerManProfit
									.add(orderDetailPo.getDiscount())
									.subtract(
											orderDetailPo
													.getFullReductionFreeFreight() ? productFreight
													: BigDecimal.ZERO)
									.subtract(shopOwnerProfit)
									.subtract(totalPromotion);
						}
					} else {

						// 优惠总额：买手优惠券 + 买手满减优惠
						BigDecimal totalPromotion = orderDetailPo
								.getPromotionAmount().add(
										orderDetailPo.getSellerCouponAmount());

						goodsOwnerProfit = goodsOwnerProfit
								.subtract(totalPromotion)
//								.subtract(shopOwnerProfit)
								.add(orderDetailPo.getDiscount());
					}
				} else {

					// 优惠总额：买手优惠券 + 买手满减优惠
					BigDecimal totalPromotion = orderDetailPo
							.getPromotionAmount().add(
									orderDetailPo.getSellerCouponAmount());

					shopOwnerProfit = shopOwnerProfit
							.add(orderDetailPo.getDiscount())
							.subtract(
									orderDetailPo.getFullReductionFreeFreight() ? productFreight
											: BigDecimal.ZERO)
							.subtract(totalPromotion).subtract(orderDetailPo.getRegionDiscountAmount());
				}


				// 根据退款数量计算退款利润
				shopOwnerProfit = shopOwnerProfit
						.divide(new BigDecimal(productCount), 32,
								BigDecimal.ROUND_DOWN)
						.multiply(new BigDecimal(refundCount))
						.setScale(2, BigDecimal.ROUND_DOWN);

				middlerManProfit = middlerManProfit
						.divide(new BigDecimal(productCount), 32,
								BigDecimal.ROUND_DOWN)
						.multiply(new BigDecimal(refundCount))
						.setScale(2, BigDecimal.ROUND_DOWN);

				goodsOwnerProfit = goodsOwnerProfit
						.divide(new BigDecimal(productCount), 32,
								BigDecimal.ROUND_DOWN)
						.multiply(new BigDecimal(refundCount))
						.setScale(2, BigDecimal.ROUND_DOWN);

				BigDecimal refundProductFreight = productFreight
						.divide(new BigDecimal(productCount), 32,
								BigDecimal.ROUND_DOWN)
						.multiply(new BigDecimal(refundCount))
						.setScale(2, BigDecimal.ROUND_DOWN);

				// 满减包邮邮费店主出，货头获得运费
//				goodsOwnerProfit = goodsOwnerProfit.add(orderDetailPo
//						.getFullReductionFreeFreight() ? productFreight
//						: BigDecimal.ZERO);

				if (freightRefundAmount.compareTo(BigDecimal.ZERO) == 0)
					goodsOwnerProfit = goodsOwnerProfit.add(orderDetailPo.getFullReductionFreeFreight() ? refundProductFreight
							: BigDecimal.ZERO).add(taxRefundAmount);
				else
					goodsOwnerProfit = goodsOwnerProfit.add(refundProductFreight)
							.add(taxRefundAmount);

				// 如果是货头
				if (chainPo.getIndexInChain() == 0
						&& orderPo.getSellerId() != orderPo.getGoodsOwnerId()) {

					refundedProfitHashMap.put(orderPo.getGoodsOwnerId(),
							goodsOwnerProfit);
				}
				// 如果是店主
				else if (chainPo.getSellerId().longValue() == orderPo
						.getSellerId().longValue()) {

					refundedProfitHashMap.put(orderPo.getSellerId(),
							shopOwnerProfit);
					serviceIncome = shopOwnerProfit;
				}
				// 如果是中间商
				else {

					refundedProfitHashMap.put(chainPo.getSellerId(),
							middlerManProfit);
				}

				i++;
			}

			if (orderPo.getSalesman() != 0) {

				refundedProfitHashMap.put(orderPo.getSalesman(), serviceIncome);
			}
		}

		return refundedProfitHashMap;
	}

	/**
	 * 接单之后，所有订单上商品所有款都退完后，订单变更为用户取消，给商家结算剩余金额
	 * 
	 * @param orderId
	 */
	public static void settleLeftAmtAfterCancelled(long orderId) {

		YmatouEasyCall settleLeftAmtAfterCancelled = new YmatouEasyCall("",
				"POST", "JSON");
		String json = "{\"orderId\":" + orderId + "}";

		settleLeftAmtAfterCancelled
				.setUrl("http://settlement.iapi.ymatou.com/api/settleLeftAmtAfterCancelled");

		settleLeftAmtAfterCancelled.setData(json);

		Logger.comment("接单后，退货退完后，订单为用户取消，给商家结算剩余金额");
		try {
			settleLeftAmtAfterCancelled.callService();
		} catch (Exception e) {

			e.printStackTrace();

		}
	}

	/**
	 * 接单之后，所有订单上商品所有款都退完后，订单变更为用户取消，给商家结算剩余金额
	 * 
	 * @param orderId
	 */
	public static void supplementRefund(long orderId) {

		YmatouEasyCall settleLeftAmtAfterCancelled = new YmatouEasyCall("",
				"POST", "JSON");
		String json = "{}";

		settleLeftAmtAfterCancelled
				.setUrl("http://sqoptrade.iapi.shop2cn.com/api/refund/supplementRefund");

		settleLeftAmtAfterCancelled.setData(json);

		try {
			settleLeftAmtAfterCancelled.callService();
		} catch (Exception e) {

			e.printStackTrace();

		}
	}

	/**
	 * 计算商品可退金额
	 * 
	 * @param po
	 * @return
	 */
	public static BigDecimal getOrderDetailPaidAmountExcludeFreight(
			OrderDetailPo po, int productCount, Boolean includeServiceAmount) {

		BigDecimal refundAmount = Utils.zeroIfNull(po.getProductPrice())
				.multiply(new BigDecimal(po.getProductCount()))
				.add(Utils.zeroIfNull(po.getDiscount()))
				.subtract(Utils.zeroIfNull(po.getYmtCouponAmount()))
				.subtract(Utils.zeroIfNull(po.getSellerCouponAmount()))
				.subtract(Utils.zeroIfNull(po.getPromotionAmount()))
				.subtract(Utils.zeroIfNull(po.getYmtPromotionAmount()))
				.subtract(Utils.zeroIfNull(po.getIntegralDeductionAmount()))
				.subtract(Utils.zeroIfNull(po.getRegionDiscountAmount()));

		if (po.getProductCount() != productCount) {

			refundAmount = refundAmount
					.divide(new BigDecimal(po.getProductCount()),
							MathContext.DECIMAL32)
					.setScale(2, RoundingMode.DOWN)
					.multiply(new BigDecimal(productCount));
		}

		refundAmount = refundAmount.add(includeServiceAmount ? po
				.getServiceAmount() : BigDecimal.ZERO);

		return refundAmount;
	}

	/**
	 * 计算订单上的最大可退金额（仅退款适用）
	 * 
	 * @param order
	 * @return
	 */
	public static BigDecimal getOrderMaxRefundAmount(Order order) {

		BigDecimal orderMaxrefundAmount = order.getOrderPayableAmount()
				.subtract(order.getOrderTaxFee())
				.subtract(order.getOrderFreight())
				.subtract(order.getOrderServiceAmount())
				.subtract(order.getOrderIntegralDeductionAmount());

		// 计算退款单上已经退款完成的退款金额
		BigDecimal refundedAmount = getAlreadyRefundedTotalProductAmount(order
				.getOrderId());

		orderMaxrefundAmount = orderMaxrefundAmount.subtract(refundedAmount);

		return orderMaxrefundAmount;
	}

	public static BigDecimal getAlreadyRefundedTotalProductAmount(Long orderId) {

		List<RefundBill> refundBills = refundBillWrapper
				.selectSuccessByOrderId(orderId);

		BigDecimal alreadyRefundedTotalProductAmount = refundBills.stream()
				.map(RefundBill::getTotal_refund_product_amount)
				.reduce(BigDecimal.ZERO, BigDecimal::add);

		return alreadyRefundedTotalProductAmount;
	}

	/**
	 * 获取商品最大可退金额
	 */
	public static BigDecimal getOrderDetailPoMaxRefundAmount(Long orderId,
			OrderDetailPo po, int productCount) {

		BigDecimal maxRefundAmount = Utils.zeroIfNull(po.getProductPrice())
				.multiply(new BigDecimal(po.getProductCount()))
				.add(Utils.zeroIfNull(po.getDiscount()))
				.subtract(Utils.zeroIfNull(po.getYmtCouponAmount()))
				.subtract(Utils.zeroIfNull(po.getSellerCouponAmount()))
				.subtract(Utils.zeroIfNull(po.getPromotionAmount()))
				.subtract(Utils.zeroIfNull(po.getYmtPromotionAmount()))
				.subtract(Utils.zeroIfNull(po.getIntegralDeductionAmount()))
				.subtract(Utils.zeroIfNull(po.getRegionDiscountAmount()));

		// 退款成功的退款单
		List<RefundBill> refundBills = refundBillWrapper
				.selectSuccessByOrderId(orderId);

		BigDecimal refundedAmount = BigDecimal.ZERO;

		for (RefundBill refundBill : refundBills) {

			List<RefundProductDetail> refundProductDetailList = refundProductDetailWrapper
					.selectByRefundNoAndOrderId(refundBill.getRefund_no(),
							orderId);

			// 对应catalogId退款详情
			RefundProductDetail refundProductDetail = refundProductDetailList
					.stream()
					.filter(refundDetail -> refundDetail.getCatalog_id()
							.equalsIgnoreCase(po.getCatalogId())).findFirst()
					.orElse(null);

			if (null != refundProductDetail)
				refundedAmount = refundedAmount.add(refundProductDetail
						.getRefund_product_amount());
		}

		maxRefundAmount = maxRefundAmount.subtract(refundedAmount);

		if (po.getProductCount() != productCount) {

			maxRefundAmount = maxRefundAmount
					.divide(new BigDecimal(po.getProductCount()),
							MathContext.DECIMAL32)
					.setScale(2, RoundingMode.DOWN)
					.multiply(new BigDecimal(productCount));
		}

		return maxRefundAmount;
	}

	/**
	 * 计算商品最大可退运费
	 * 
	 * @param orderDetailPo
	 * @return
	 */
	public static BigDecimal getMaxCanRefundFreight(
			OrderDetailPo orderDetailPo, BigDecimal productFreight) {

		if (orderDetailPo.getFullReductionFreeFreight())
			return BigDecimal.ZERO;
		else
			return productFreight;
	}
	
	public static long getMaxCanRefundIntegral(OrderDetailPo orderDetailPo,
			int refundProcutCount) {
		
		if (orderDetailPo.getProductCount() == refundProcutCount)
			return orderDetailPo.getIntegral();

		long avgIntegral = orderDetailPo.getIntegral()
				/ orderDetailPo.getProductCount();

		return avgIntegral * refundProcutCount;
	}

	/**
	 * 计算商品可退税费
	 * 
	 * @param po
	 * @return
	 */
	public static BigDecimal getOrderDetailTaxFeeAmount(OrderDetailPo po,
			int productCount) {

		BigDecimal refundAmount = Utils.zeroIfNull(po.getTaxFee())
				.multiply(new BigDecimal(productCount))
				.setScale(2, BigDecimal.ROUND_DOWN);

		return refundAmount;
	}

	public static Boolean isAllRefunded(Long orderId,
			List<OrderDetailPo> orderDetailList) {

		Boolean isAllRefunded = false;

		for (OrderDetailPo orderDetailPo : orderDetailList) {

			Integer productCount = orderDetailPo.getProductCount();

			RefundBillPo refundBillPo = orderShardingWapper
					.selectShenqiRefundBillByOrderIdAndCatalogId(orderId,
							orderDetailPo.getCatalogId());

			if (null == refundBillPo || refundBillPo.getRefundStatus() == -1
					|| refundBillPo.getProductCount() < productCount)
				isAllRefunded = false;
			else
				isAllRefunded = true;
		}

		return isAllRefunded;
	}

	/**
	 * 判断是否整单退款
	 * 
	 * @return
	 */
	public static Boolean isEntireRefunded(Long orderId) {

		OrderPo po = orderShardingWapper.selectOrderbyOrderId(orderId);

		if (SqTradingCallService.isCanceledOrder(po)
				&& po.getCancelReason().equalsIgnoreCase("货或款全部退完，订单自动取消"))
			return true;
		else
			return false;
	}

	/**
	 * 退款服务同步到es
	 */
	public static void syncNotSyncedEsRecord() throws Exception {

		YmatouEasyCall syncNotSyncedEsRecordCall = new YmatouEasyCall("",
				"POST", "JSON");
		String json = "{}";

		syncNotSyncedEsRecordCall
				.setUrl("http://sqrefund.iapi.shop2cn.com/api/job/syncNotSyncedEsRecord");

		syncNotSyncedEsRecordCall.setData(json);

		try {
			syncNotSyncedEsRecordCall.callService();
		} catch (Exception e) {

			e.printStackTrace();
		}
	}

	/**
	 * 退款服务同步到交易
	 */
	public static void syncNotSyncedRefundBill() throws Exception {

		YmatouEasyCall syncNotSyncedRefundBillCall = new YmatouEasyCall("",
				"POST", "JSON");
		String json = "{}";

		syncNotSyncedRefundBillCall
				.setUrl("http://sqrefund.iapi.shop2cn.com/api/job/syncNotSyncedRefundBill");

		syncNotSyncedRefundBillCall.setData(json);

		try {
			syncNotSyncedRefundBillCall.callService();

			Thread.sleep(2000);
		} catch (Exception e) {

			e.printStackTrace();
		}
	}

	/**
	 * 
	 * @param catalogId
	 * @param refundFreightAmount
	 * @param refundProductAmount
	 * @param refundTaxAmount
	 * @param refundProductNum
	 */
	public static PartProductRefundVo buildPartProductRefundVo(
			String catalogId, BigDecimal refundFreightAmount,
			BigDecimal refundProductAmount, BigDecimal refundTaxAmount,
			int refundProductNum) {

		PartProductRefundVo partProductRefundVo = new PartProductRefundVo();

		partProductRefundVo.setCatalogId(catalogId);
		partProductRefundVo.setRefundFreightAmount(refundFreightAmount);
		partProductRefundVo.setRefundProductAmount(refundProductAmount);
		partProductRefundVo.setRefundProductNum(refundProductNum);
		partProductRefundVo.setRefundTaxAmount(refundTaxAmount);

		return partProductRefundVo;
	}

	/**
	 * 买家申请退款
	 * @param orderId
	 * @param buyerId
	 * @throws Exception
	 */
	public static String createFullRefundByBuyerId(Long orderId, Long buyerId) throws Exception {

		FullRefundReq fullRefundReq = new FullRefundReq();
		FullRefundCall fullRefundCall = new FullRefundCall();

		fullRefundReq.setOrderId(orderId);
		fullRefundReq.setUserId(buyerId);
		fullRefundReq.setCsId(1234L);
		fullRefundReq.setRemark("买家申请退款");

		fullRefundCall.setData(fullRefundReq);
		fullRefundCall.callService();
		
		RefundBill refundBill = refundBillWrapper.selectByOrderId(orderId).get(
				0);
		
		return refundBill.getRefund_no();
	}
	
	/**
	 * 买家申请退货退款
	 * @param orderId
	 * @param buyerId
	 * @throws Exception
	 */
	public static String createFullRefundGoods(Long orderId, Long buyerId) throws Exception {

		FullRefundGoodsReq fullRefundGoodsReq = new FullRefundGoodsReq();
		FullRefundGoodsCall fullRefundGoodsCall = new FullRefundGoodsCall();

		fullRefundGoodsReq.setOrderId(orderId);
		fullRefundGoodsReq.setUserId((long) buyerId);
		fullRefundGoodsReq.setCsId(1234L);
		fullRefundGoodsReq.setRemark("remar阿斯达卡");
		fullRefundGoodsReq.setLiabilityType(null);
		fullRefundGoodsReq.setRefundExtType(null);
		fullRefundGoodsReq.setRefundReasonCode(-1);
		fullRefundGoodsReq.setHasRefundGoods(false);

		fullRefundGoodsCall.setData(fullRefundGoodsReq);
		fullRefundGoodsCall.callService();
		
		RefundBill refundBill = refundBillWrapper.selectByOrderId(orderId).get(
				0);
		
		return refundBill.getRefund_no();
	}
	
	/**
	 * 创建一个整单退款成功的退款单
	 * 
	 * @param orderId
	 * @param userId
	 * @param paymentId
	 * @throws Exception
	 */
	public static void createFullRefundSuccess(Long orderId, Long goodsOwnerId,
			Long paymentId, Long userId) throws Exception {

		FullRefundReq fullRefundReq = new FullRefundReq();
		FullRefundCall fullRefundCall = new FullRefundCall();

		fullRefundReq.setOrderId(orderId);
		fullRefundReq.setUserId(goodsOwnerId);
		fullRefundReq.setCsId(1234L);
		fullRefundReq.setRemark("整单退款成功");

		fullRefundCall.setData(fullRefundReq);
		fullRefundCall.callService();

		// 退款服务同步到交易
		RefundService.syncNotSyncedRefundBill();

		RefundService.supplementRefund(orderId);

		// 退款服务同步到交易
//		RefundService.syncNotSyncedRefundBill();
//
//		// 退款提交到网关
//		UserRefundFundDetailPo record = new UserRefundFundDetailPo();
//
//		Calendar calendar = Calendar.getInstance();
//		calendar.setTime(new Date());
//		calendar.add(Calendar.HOUR, -24);
//
//		record.setPaymentId(paymentId);
//		record.setUpdateTime(calendar.getTime());
//
//		orderShardingWapper.userRefundFundDetailMapper
//				.updateByPrimaryKeySelective(record);
//
//		RefundService.supplementRefund(orderId);
//
//		// 支付网关退款回调
//		if (goodsOwnerId == macaoCDFGoodsOwnerId)
//			return;
//		else
//			SQPayGateWayCallService.refundNotifyCall("13",
//					paymentId.toString(), userId.intValue());
	}

	/**
	 * 创建一个整单退款失败的退款单
	 * 
	 * @param orderId
	 * @param userId
	 * @param paymentId
	 * @throws Exception
	 */
	public static void createFullRefundFailed(Long orderId, Long goodsOwnerId,
			Long paymentId, Long userId) throws Exception {

		FullRefundReq fullRefundReq = new FullRefundReq();
		FullRefundCall fullRefundCall = new FullRefundCall();

		fullRefundReq.setOrderId(orderId);
		fullRefundReq.setUserId(goodsOwnerId);
		fullRefundReq.setCsId(1234L);
		fullRefundReq.setRemark("整单退款失败");

		fullRefundCall.setData(fullRefundReq);
		fullRefundCall.callService();

		// 退款服务同步到交易
		RefundService.syncNotSyncedRefundBill();

		RefundService.supplementRefund(orderId);
	}

	/**
	 * 创建一个整单退款被拒绝的退款单
	 * 
	 * @param orderId
	 * @param userId
	 * @param paymentId
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static String createFullRefundRejected(Long orderId, Long userId,
			Long paymentId) throws ClientProtocolException, IOException {

		FullRefundReq fullRefundReq = new FullRefundReq();
		FullRefundCall fullRefundCall = new FullRefundCall();

		fullRefundReq.setOrderId(orderId);
		fullRefundReq.setUserId(userId);
		fullRefundReq.setCsId(1234L);
		fullRefundReq.setRemark("整单退款被拒绝");
		fullRefundReq.setLiabilityType(1);
		fullRefundReq.setRefundExtType(2);
		fullRefundReq.setRefundReasonCode(-1);
		fullRefundReq.setHasRefundGoods(false);

		fullRefundCall.setData(fullRefundReq);
		fullRefundCall.callService();

		RefundBill refundBill = refundBillWrapper.selectByOrderId(orderId).get(
				0);

		RefundService.auditRefund(refundBill.getGoods_owner_id(),
				refundBill.getCurrent_review_mch_id(), 1,
				refundBill.getRefund_no(), false);
		
		return refundBill.getRefund_no();
	}
	
	public static String createPartProductRefund(Long orderId,
			OrderDetailPo orderDetailPo, Long goodsOwnerId,
			Long userId) throws Exception {

		PartProductRefundReq partProductRefundReq = new PartProductRefundReq();
		PartProductRefundCall partProductRefundCall = new PartProductRefundCall();

		int productCount = 1;

		BigDecimal refundProductAmount = RefundService
				.getOrderDetailPoMaxRefundAmount(orderId, orderDetailPo,
						productCount);
		BigDecimal refundTaxFeeAmount = RefundService
				.getOrderDetailTaxFeeAmount(orderDetailPo, productCount);
		BigDecimal refundFreightAmount = RefundService.getMaxCanRefundFreight(
				orderDetailPo, orderDetailPo.getFreight());

		PartProductRefundVo partProductRefundVo = RefundService
				.buildPartProductRefundVo(orderDetailPo.getCatalogId(),
						refundFreightAmount, refundProductAmount,
						refundTaxFeeAmount, 1);

		partProductRefundReq.setUserId(goodsOwnerId);
		partProductRefundReq.setCsId(1234L);
		partProductRefundReq.setPartProductRefundVoList(Arrays
				.asList(partProductRefundVo));
		partProductRefundReq.setOrderId(orderId);
		partProductRefundReq.setRemark("部分退货退款成功");
		partProductRefundReq.setLiabilityType(1);
		partProductRefundReq.setRefundExtType(2);
		partProductRefundReq.setRefundReasonCode(-1);
		partProductRefundReq.setHasRefundGoods(false);

		partProductRefundCall.setData(partProductRefundReq);
		partProductRefundCall.callService();
		
		RefundBill refundBill = refundBillWrapper.selectByOrderId(orderId).get(
				0);

		return refundBill.getRefund_no();
	}

	/**
	 * 创建一个部分退货退款成功的退款单
	 * 
	 * @param orderId
	 * @param userId
	 * @param paymentId
	 * @throws Exception
	 */
	public static String createPartProductRefundSuccess(Long orderId,
			OrderDetailPo orderDetailPo, Long goodsOwnerId, Long paymentId,
			Long userId) throws Exception {

		PartProductRefundReq partProductRefundReq = new PartProductRefundReq();
		PartProductRefundCall partProductRefundCall = new PartProductRefundCall();
		
		int productCount = 1;
		
		BigDecimal refundProductAmount = RefundService
				.getOrderDetailPoMaxRefundAmount(orderId, orderDetailPo,
						productCount);
		BigDecimal refundTaxFeeAmount = RefundService.getOrderDetailTaxFeeAmount(orderDetailPo, productCount);
		BigDecimal refundFreightAmount = RefundService.getMaxCanRefundFreight(orderDetailPo, orderDetailPo.getFreight());

		PartProductRefundVo partProductRefundVo = RefundService
				.buildPartProductRefundVo(orderDetailPo.getCatalogId(),
						refundFreightAmount, refundProductAmount,
						refundTaxFeeAmount, 1);

		partProductRefundReq.setUserId(goodsOwnerId);
		partProductRefundReq.setCsId(1234L);
		partProductRefundReq.setPartProductRefundVoList(Arrays
				.asList(partProductRefundVo));
		partProductRefundReq.setOrderId(orderId);
		partProductRefundReq.setRemark("部分退货退款成功");
		partProductRefundReq.setLiabilityType(1);
		partProductRefundReq.setRefundExtType(2);
		partProductRefundReq.setRefundReasonCode(-1);
		partProductRefundReq.setHasRefundGoods(false);

		partProductRefundCall.setData(partProductRefundReq);
		partProductRefundCall.callService();

		// 退款服务同步到交易
		RefundService.syncNotSyncedRefundBill();

		// 退款提交到网关
		UserRefundFundDetailPo record = new UserRefundFundDetailPo();

		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date());
		calendar.add(Calendar.MINUTE, -6);

		record.setPaymentId(paymentId);
		record.setUpdateTime(calendar.getTime());

		orderShardingWapper.userRefundFundDetailMapper
				.updateByPrimaryKeySelective(record);

		RefundService.supplementRefund(orderId);

		// 支付网关退款回调
		if (goodsOwnerId != macaoCDFGoodsOwnerId)
			SQPayGateWayCallService.refundNotifyCall("13",
					paymentId.toString(), userId.intValue());
		
		Thread.sleep(3000);

		RefundBill refundBill = refundBillWrapper.selectByOrderId(orderId).stream()
				.filter(po-> po.getRefund_type() == 2)
				.collect(Collectors.toList())
				.get(0);
		
		return refundBill.getRefund_no();
	}

	/**
	 * 创建一个部分退货退款成功的退款单
	 * 
	 * @param orderId
	 * @param orderDetailPo
	 * @param goodsOwnerId
	 * @param paymentId
	 * @param userId
	 * @throws Exception
	 */
	public static String createOnePartProductRefundSuccess(Long orderId,
			OrderDetailPo orderDetailPo, Long goodsOwnerId, Long paymentId,
			Long userId, int refundCount) throws Exception {

		PartProductRefundReq partProductRefundReq = new PartProductRefundReq();
		PartProductRefundCall partProductRefundCall = new PartProductRefundCall();

		BigDecimal maxProductAmount = RefundService
				.getOrderDetailPoMaxRefundAmount(orderId, orderDetailPo,
						refundCount);

		BigDecimal taxFeeAmount = RefundService.getOrderDetailTaxFeeAmount(
				orderDetailPo, refundCount);
		
		BigDecimal freightAmount = RefundService
				.getMaxCanRefundFreight(orderDetailPo,
						orderDetailPo.getFreight());

		PartProductRefundVo partProductRefundVo = RefundService
				.buildPartProductRefundVo(orderDetailPo.getCatalogId(),
						freightAmount, maxProductAmount, taxFeeAmount,
						refundCount);

		partProductRefundReq.setUserId(goodsOwnerId);
		partProductRefundReq.setCsId(1234L);
		partProductRefundReq.setPartProductRefundVoList(Arrays
				.asList(partProductRefundVo));
		partProductRefundReq.setOrderId(orderId);
		partProductRefundReq.setRemark("部分退货退款成功");
		partProductRefundReq.setLiabilityType(1);
		partProductRefundReq.setRefundExtType(2);
		partProductRefundReq.setRefundReasonCode(-1);
		partProductRefundReq.setHasRefundGoods(false);

		partProductRefundCall.setData(partProductRefundReq);
		partProductRefundCall.callService();

		// 退款服务同步到交易
		RefundService.syncNotSyncedRefundBill();

		// 退款提交到网关
		UserRefundFundDetailPo record = new UserRefundFundDetailPo();

		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date());
		calendar.add(Calendar.HOUR, -24);

		record.setPaymentId(paymentId);
		record.setUpdateTime(calendar.getTime());

		orderShardingWapper.userRefundFundDetailMapper
				.updateByPrimaryKeySelective(record);

		RefundService.supplementRefund(orderId);

		// 支付网关退款回调
		if (goodsOwnerId != macaoCDFGoodsOwnerId)
			SQPayGateWayCallService.refundNotifyCall("13",
					paymentId.toString(), userId.intValue());
		
		Thread.sleep(3000);
		
		RefundBill refundBill = refundBillWrapper.selectByOrderId(orderId).get(
				0);
		
		return refundBill.getRefund_no();
	}
	
	public static String createPartProductRefundRejected(Long orderId,
			OrderDetailPo orderDetailPo, Long goodsOwnerId, Long paymentId, Long userId)
			throws Exception {

		PartProductRefundReq partProductRefundReq = new PartProductRefundReq();
		PartProductRefundCall partProductRefundCall = new PartProductRefundCall();

		int productCount = 1;

		BigDecimal refundProductAmount = RefundService
				.getOrderDetailPoMaxRefundAmount(orderId, orderDetailPo,
						productCount);
		BigDecimal refundTaxFeeAmount = RefundService
				.getOrderDetailTaxFeeAmount(orderDetailPo, productCount);
		BigDecimal refundFreightAmount = RefundService.getMaxCanRefundFreight(
				orderDetailPo, orderDetailPo.getFreight());

		PartProductRefundVo partProductRefundVo = RefundService
				.buildPartProductRefundVo(orderDetailPo.getCatalogId(),
						refundFreightAmount, refundProductAmount,
						refundTaxFeeAmount, 1);

		partProductRefundReq.setUserId(goodsOwnerId);
		partProductRefundReq.setCsId(1234L);
		partProductRefundReq.setPartProductRefundVoList(Arrays
				.asList(partProductRefundVo));
		partProductRefundReq.setOrderId(orderId);
		partProductRefundReq.setRemark("部分退货退款成功");
		partProductRefundReq.setLiabilityType(1);
		partProductRefundReq.setRefundExtType(2);
		partProductRefundReq.setRefundReasonCode(-1);
		partProductRefundReq.setHasRefundGoods(false);

		partProductRefundCall.setData(partProductRefundReq);
		partProductRefundCall.callService();

		RefundBill refundBill = refundBillWrapper.selectByOrderId(orderId).get(
				0);

		// 退款服务同步到交易
		RefundService.syncNotSyncedRefundBill();

		// 退款提交到网关
		UserRefundFundDetailPo record = new UserRefundFundDetailPo();

		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date());
		calendar.add(Calendar.MINUTE, -6);

		record.setPaymentId(paymentId);
		record.setUpdateTime(calendar.getTime());

		orderShardingWapper.userRefundFundDetailMapper
				.updateByPrimaryKeySelective(record);

		RefundService.supplementRefund(orderId);

		return refundBill.getRefund_no();
	}

	/**
	 * 创建一个仅退款成功的退款单
	 * 
	 * @param orderId
	 * @param userId
	 * @param paymentId
	 * @throws Exception
	 */
	public static String createPartAmountRefundSuccess(Long orderId,
			Long goodsOwnerId, Long paymentId, Long userId,
			BigDecimal refundAmount) throws Exception {

		PartAmountRefundReq partAmountRefundReq = new PartAmountRefundReq();
		PartAmountRefundCall partAmountRefundCall = new PartAmountRefundCall();

		partAmountRefundReq.setUserId(goodsOwnerId);
		partAmountRefundReq.setCsId(1234L);
		partAmountRefundReq.setApplyAmount(refundAmount);
		partAmountRefundReq.setOrderId(orderId);
		partAmountRefundReq.setRemark("仅退款成功");
		partAmountRefundReq.setLiabilityType(1);
		partAmountRefundReq.setRefundExtType(2);
		partAmountRefundReq.setRefundReasonCode(-1);
		partAmountRefundReq.setHasRefundGoods(false);

		partAmountRefundCall.setData(partAmountRefundReq);
		partAmountRefundCall.callService();

		// 退款服务同步到交易
		RefundService.syncNotSyncedRefundBill();

		// 退款提交到网关
		UserRefundFundDetailPo record = new UserRefundFundDetailPo();

		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date());
		calendar.add(Calendar.MINUTE, -6);

		record.setPaymentId(paymentId);
		record.setUpdateTime(calendar.getTime());

		orderShardingWapper.userRefundFundDetailMapper
				.updateByPrimaryKeySelective(record);

		RefundService.supplementRefund(orderId);

		// 支付网关退款回调
		if (goodsOwnerId != macaoCDFGoodsOwnerId)
			SQPayGateWayCallService.refundNotifyCall("13",
					paymentId.toString(), userId.intValue());

		Thread.sleep(3000);
		
		RefundBill refundBill = refundBillWrapper.selectByOrderId(orderId).stream()
				.filter(po-> po.getRefund_type() == 1)
				.collect(Collectors.toList())
				.get(0);
		
		return refundBill.getRefund_no();
	}

	/**
	 * 创建一个仅退款被拒绝的退款单
	 * 
	 * @param orderId
	 * @param userId
	 * @param paymentId
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static String createPartAmountRefundRejected(Long orderId,
			Long userId, Long paymentId) throws ClientProtocolException,
			IOException {

		PartAmountRefundReq partAmountRefundReq = new PartAmountRefundReq();
		PartAmountRefundCall partAmountRefundCall = new PartAmountRefundCall();

		partAmountRefundReq.setUserId(userId);
		partAmountRefundReq.setCsId(1234L);
		partAmountRefundReq.setApplyAmount(BigDecimal.TEN);
		partAmountRefundReq.setOrderId(orderId);
		partAmountRefundReq.setRemark("仅退款被拒绝");
		partAmountRefundReq.setLiabilityType(1);
		partAmountRefundReq.setRefundExtType(2);
		partAmountRefundReq.setRefundReasonCode(-1);
		partAmountRefundReq.setHasRefundGoods(false);

		partAmountRefundCall.setData(partAmountRefundReq);
		partAmountRefundCall.callService();
		
		RefundBill refundBill = refundBillWrapper.selectByOrderId(orderId).get(
				0);

		RefundService.auditRefund(refundBill.getGoods_owner_id(),
				refundBill.getCurrent_review_mch_id(), 0,
				refundBill.getRefund_no(), false);
		
		return refundBill.getRefund_no();
	}

	public static void auditRefund(Long merchantId, Long reviewerId,
			int currentMchRefundStatus, String refundNo, Boolean pass)
			throws ClientProtocolException, IOException {

		AuditRefundReq auditRefundReq = new AuditRefundReq();
		AuditRefundCall auditRefundCall = new AuditRefundCall();

		auditRefundReq.setCurrentMchRefundStatus(currentMchRefundStatus);
		auditRefundReq.setMerchantId(merchantId);
		auditRefundReq.setPass(pass);
		auditRefundReq.setRefundNo(refundNo);
		auditRefundReq.setReviewerId(reviewerId);

		auditRefundCall.setData(auditRefundReq);
		auditRefundCall.callService();
	}
	
	public static void auditRefundGoods(Long merchantId, Long reviewerId,
			int currentMchRefundStatus, String refundNo, Boolean pass)
			throws ClientProtocolException, IOException {

		AuditRefundReq auditRefundReq = new AuditRefundReq();
		AuditRefundCall auditRefundCall = new AuditRefundCall();
		
		auditRefundReq.setMerchantId(merchantId);
		auditRefundReq.setPass(pass);
		auditRefundReq.setRefundNo(refundNo);
		auditRefundReq.setReviewerId(reviewerId);
		auditRefundReq.setCurrentMchRefundStatus(currentMchRefundStatus);
		
		RefundAddressVo refundAddressVo = RefundAddressVo.buildStandardRefundAddress();
					
		auditRefundReq.setRefundAddress(refundAddressVo);

		auditRefundCall.setData(auditRefundReq);
		auditRefundCall.callService();
	}
	
	/**
	 * 保存退货时的物流信息
	 * 
	 * @param goodsOwnerId
	 * @param refundNo
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	public static void saveOrUpdateRefundGoodsExpressInfoList(
			long goodsOwnerId, String refundNo, Long userId) throws ClientProtocolException,
			IOException {

		SaveOrUpdateRefundGoodsExpressInfoListReq saveOrUpdateRefundGoodsExpressInfoListReq = new SaveOrUpdateRefundGoodsExpressInfoListReq();
		SaveOrUpdateRefundGoodsExpressInfoListCall saveOrUpdateRefundGoodsExpressInfoListCall = new SaveOrUpdateRefundGoodsExpressInfoListCall();

		RefundGoodsExpressInfoVo refundGoodsExpressInfoVo = new RefundGoodsExpressInfoVo();

		refundGoodsExpressInfoVo.setExpressBillNo("expressBillNo");
		refundGoodsExpressInfoVo.setExpressCode("expressCode");
		refundGoodsExpressInfoVo.setExpressCompany("expressCompany");

		saveOrUpdateRefundGoodsExpressInfoListReq.setExpressList(Arrays
				.asList(refundGoodsExpressInfoVo));
		saveOrUpdateRefundGoodsExpressInfoListReq.setMerchantId(goodsOwnerId);
		saveOrUpdateRefundGoodsExpressInfoListReq.setRefundNo(refundNo);
		saveOrUpdateRefundGoodsExpressInfoListReq.setUserId(userId);
		saveOrUpdateRefundGoodsExpressInfoListReq.setUsername(TestDataManager
				.randomStr(5));

		saveOrUpdateRefundGoodsExpressInfoListCall
				.setData(saveOrUpdateRefundGoodsExpressInfoListReq);
		saveOrUpdateRefundGoodsExpressInfoListCall.callService();
	}

	public static void main(String... args) throws Exception {

		// 退款服务同步到交易
		RefundService.syncNotSyncedRefundBill();

		// 退款提交到网关
		UserRefundFundDetailPo record = new UserRefundFundDetailPo();

		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date());
		calendar.add(Calendar.MINUTE, -6);

		record.setPaymentId(1850033006L);
		record.setUpdateTime(calendar.getTime());

		orderShardingWapper.userRefundFundDetailMapper
				.updateByPrimaryKeySelective(record);

		RefundService.supplementRefund(1550033006);

		// 支付网关退款回调
		SQPayGateWayCallService.refundNotifyCall("13", "1850033006",
				502603006);
	}
}
